/* Copyright 1993 Michael B. Johnson
 * Permission to use, copy, modify, and distribute this
 * software and its documentation for any non-commercial 
 * purpose and without fee is hereby granted, provided that the 
 * above copyright notice appears in all copies.  Michael B. Johnson
 * makes no representations about the suitability of this
 * software for any purpose.  It is provided "as is" without
 * express or implied warranty.
 *
 * Permission to use, copy, modify or distribute this software
 * and its documentation for any commercial purpose must be
 * confirmed in writing with Michael B. Johnson.  He can be
 * contacted at:
 *              20 Ames St. E15-023G    
 *              Cambridge, MA 02141
 *              (617) 547 0563
 *              
 */


#import "WWTCLVarTrace.h"
#import "WWTCLInterp.h"

// import one UI just so it knows about the methods...
#import "WWSlider.h"

@implementation WWTCLVarTrace


- initWithVarName:(const char *)newVarName proc:(Tcl_VarTraceProc *)newTraceProcPointer datum:(ClientData)newDatum delegate:newDelegate interp:newInterp
{
  [super init];

  freeingMyself = NO;
  varName = NXCopyStringBuffer(newVarName);
  uiObject = (id)newDatum;
  delegate = newDelegate;
  tclInterp = newInterp;
  traceProcPointer = newTraceProcPointer;

  return self;
}

- initWithVarName2:(const char *)newVarName1 :(const char *)newVarName2 proc:(Tcl_VarTraceProc *)newTraceProcPointer datum:(ClientData)newDatum delegate:newDelegate interp:newInterp
{
  [super init];

  freeingMyself = NO;
  varName = (char *)malloc(3 + strlen(newVarName1) + strlen(newVarName2));
  sprintf(varName, "%s(%s)", newVarName1, newVarName2);
  uiObject = (id)newDatum;
  delegate = newDelegate;
  tclInterp = newInterp;
  traceProcPointer = newTraceProcPointer;

  return self;
}

- awake
{
  [super awake];
  freeingMyself = NO;
  return self;
}

- free
{
  //NXLogError("%s %d being free'ed\n", [[self class] name], self);
  if (freeingMyself)  // don't want to recurse here when freeing the trace...
  {  return nil;
  }
  freeingMyself = YES;
  [self removeTrace];
  if (varName) {  free(varName); }
  return [super free];
}

- (BOOL)matchWithVarName:(const char *)newVarName proc:(Tcl_VarTraceProc *)newTraceProcPointer datum:(ClientData)newDatum delegate:newDelegate
{
  if (strcmp(varName, newVarName))
  {  return NO;
  }
  if (uiObject != (id)newDatum)
  {  return NO;
  }
  if (delegate != newDelegate)
  {  return NO;
  }
  if (traceProcPointer != newTraceProcPointer)
  {  return NO;
  }

  return YES;
}

- (const char *)varName {  return varName; }
- tclInterp {  return tclInterp; }
- datum {  return uiObject; }
- uiObject {  return uiObject; }
- delegate { return delegate; }
- (Tcl_VarTraceProc *)traceProcPointer { return traceProcPointer; }

// just so it won't complain...
- tclVarChanged:(const char *)aVarName { return self; }

- setStringValue:(const char *)newValue
{
  [uiObject setStringValue:newValue];
  if (delegate) {  [delegate tclVarChanged:varName]; }
  return self;
}

- executeTrace
{
  [uiObject evaluateSelf];
  if (delegate) {  [delegate tclVarChanged:varName]; }
  return self;
}

- removeTrace  // need to have the interp around to do this...
{
   [tclInterp _untraceWritesOn:varName calling:traceProcPointer usingData:uiObject];
   return self;
}


@end
